package com.oig.sys.auth.controller;


import com.oig.common.exception.BadRequestException;
import com.oig.common.module.SysResponse;
import com.oig.common.util.JsonUtil;
import com.oig.common.validator.GroupAdd;
import com.oig.common.validator.GroupEdit;
import com.oig.sys.auth.dto.ResourceDto;
import com.oig.sys.auth.dto.ResourceGQLCondDto;
import com.oig.sys.auth.service.ITbResourceColumnService;
import com.oig.sys.auth.service.ITbResourceService;
import com.oig.sys.auth.vo.ResourceColumnVo;
import com.oig.sys.auth.vo.ResourceVo;
import com.oig.sys.log.annotation.SysLog;
import com.oig.sys.security.util.SecurityUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 菜单跟接口权限分开，是否必要？
 * 一个菜单或者按钮，可能需要用到多个接口,查询接口应该也是要配置权限的
 * 分开的话， 灵活性会更高，但是程序更复杂，配置会更麻烦，
 * 考虑到配置基本上只配置一次，先分开做，支持更高灵活性
 *
 */
@Tag(name = "5-菜单按钮管理")
@RestController
@RequestMapping("/resource")
@Slf4j
public class TbResourceController {


    private final ITbResourceService resourceService;
    private final ITbResourceColumnService resourceColumnService;

    @Autowired
    public TbResourceController(ITbResourceService resourceService,
                                ITbResourceColumnService resourceColumnService){
        this.resourceService = resourceService;
        this.resourceColumnService = resourceColumnService;
    }

    @PreAuthorize("@pms.hasPermission('/resource/addResource')")
    @SysLog(value="添加菜单按钮",apiUrl="/resource/addResource")
    @Operation(summary = "添加菜单按钮,菜单按钮展现用")
    @PostMapping("/addResource")
    public ResourceVo addResource(@RequestBody @Validated(GroupAdd.class) ResourceDto resourceDto){
        log.info("add resourceDto:{}",resourceDto.toString());
        if (SecurityUtil.getDefineUserMain().getTenantId()!=0){
            throw new BadRequestException("租户无权操作");
        }
        this.tryCheck(resourceDto);
        return resourceService.addResource(resourceDto) ;
    }

    private void tryCheck(ResourceDto resourceDto){
        if (StringUtils.isNotBlank(resourceDto.getQueryConditionCfg())){
            try {
                JsonUtil.toList(resourceDto.getQueryConditionCfg(), ResourceGQLCondDto.class);
            } catch (Exception e){
                throw new BadRequestException("默认查询条件配置格式错误") ;
            }
        }
        if (StringUtils.isNotBlank(resourceDto.getQuerySortCfg())){
            try {
                JsonUtil.stringToCollect(resourceDto.getQuerySortCfg());
            } catch (Exception e){
                throw new BadRequestException("默认查询排序配置格式错误") ;
            }
        }
    }

    @PreAuthorize("@pms.hasPermission('/resource/updateResource')")
    @SysLog(value="修改菜单按钮",apiUrl="/resource/updateResource")
    @Operation(summary = "修改菜单按钮,菜单按钮展现用")
    @PostMapping("/updateResource")
    public ResourceVo updateResource(@RequestBody @Validated(GroupEdit.class) ResourceDto resourceDto){
        log.info("update resourceDto:{}",resourceDto.toString());
        if (SecurityUtil.getDefineUserMain().getTenantId()!=0){
            throw new BadRequestException("租户无权操作");
        }
        this.tryCheck(resourceDto);
        return resourceService.updateResource(resourceDto) ;
    }

    @PreAuthorize("@pms.hasPermission('/resource/cancelResource')")
    @SysLog(value="逻辑删除菜单按钮",apiUrl="/resource/cancelResource")
    @Operation(summary = "逻辑删除菜单按钮")
    @PostMapping(value = "/cancelResource/{resourceId}")
    public SysResponse<Integer> cancelResource(@PathVariable("resourceId") Integer resourceId){
        log.info("cancel resourceId:{}",resourceId);
        this.resourceService.cancelResource(resourceId);
        return SysResponse.ok(resourceId,"删除成功");
    }


    @PreAuthorize("@pms.hasPermission('/resource/revertResource')")
    @SysLog(value="恢复菜单按钮",apiUrl="/resource/revertResource")
    @Operation(summary = "恢复菜单按钮")
    @PostMapping(value = "/revertResource/{resourceId}")
    public SysResponse<Integer> revertResource(@PathVariable("resourceId") Integer resourceId){
        log.info("revert resourceId:{}",resourceId);
        if (SecurityUtil.getDefineUserMain().getTenantId()!=0){
            throw new BadRequestException("租户无权操作");
        }
        this.resourceService.revertResource(resourceId);
        return SysResponse.ok(resourceId,"恢复成功");
    }

    @PreAuthorize("@pms.hasPermission('/resource/delResource')")
    @SysLog(value="物理删除菜单按钮",apiUrl="/resource/delResource")
    @Operation(summary = "物理删除菜单按钮,会把菜单按钮的关联数据全部删除，如菜单的列数据，角色所拥有的权限数据全部删除")
    @PostMapping("/delResource/{resourceId}")
    public SysResponse<Integer> delResource(@PathVariable("resourceId") Integer resourceId){
        log.info("del Resource resourceId:{}", resourceId);
        if (SecurityUtil.getDefineUserMain().getTenantId()!=0){
            throw new BadRequestException("租户无权操作");
        }
        this.resourceService.delResource(resourceId);
        return SysResponse.ok(resourceId,"删除成功") ;
    }

    @PreAuthorize("@pms.hasPermission('/resource/findAllResourceTree')")
    @Operation(summary = "获取系统菜单树,获取子应用下的所有的菜单按钮，菜单管理用")
    @PostMapping(value = "/findAllResourceTree/{systemId}")
    public List<ResourceVo> findAllResourceTree(@PathVariable("systemId") Integer systemId){
        log.info("findAllResourceTree 系统id {}", systemId);
        return this.resourceService.findResourceTree(systemId);
    }

    /**
     * 菜单是在每个子应用下的
     * 默认设置一个系统管理的子应用，菜单权限等放系统管理下
     * @param systemId 应用id必传
     */
    @Operation(summary = "用户获取菜单树,获取子应用下的用户菜单树，用户登录渲染菜单用")
    @PostMapping(value = "/findResourceTree/{systemId}")
    public List<ResourceVo> findResourceTree(@PathVariable("systemId") Integer systemId){
        log.info("findResourceTree 系统id {}", systemId);
        return this.resourceService.findUserResourceTree(systemId);
    }

    @Operation(summary = "查看,查看详情，如果有子表则包含子表信息")
    @PostMapping(value = "/info/{resourceId}")
    public ResourceVo info(@PathVariable("resourceId") Integer resourceId){
        log.info("info ResourceVo id={}", resourceId) ;
        return this.resourceService.getResourceInfo(resourceId);
    }


    @Operation(summary = "根据代码获取资源信息")
    @PostMapping(value = "/getByCode")
    public ResourceVo getByCode(@RequestParam(value = "resourceCode") String resourceCode, @RequestParam(value = "userId",required=false) Integer userId){
        log.info("info ResourceVo code={}, userId={}", resourceCode, userId) ;
        return this.resourceService.getResourceInfo(resourceCode, userId);
    }


    @Operation(summary = "查询菜单列,返回菜单所有列")
    @PostMapping(value = "/getColumnList/{resourceId}")
    public List<ResourceColumnVo> getColumnList(@PathVariable("resourceId") Integer resourceId){
        log.info("get resource column list resource id={}", resourceId) ;
        return this.resourceColumnService.findAllColumnByResourceId(resourceId);
    }

}
